﻿// ===============================================================================
// XCI.NET 西安交通信息WinForm开发框架 2018 版权所有
// ===============================================================================
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using DevExpress.LookAndFeel;
using DevExpress.UserSkins;
using DevExpress.Utils;
using DevExpress.XtraBars;
using DevExpress.XtraBars.Navigation;
using DevExpress.XtraEditors;
using DevExpress.XtraEditors.Controls;
using DevExpress.XtraGrid.Columns;
using DevExpress.XtraGrid.Views.Grid;
using DevExpress.XtraLayout;
using DevExpress.XtraSplashScreen;
using DevExpress.XtraTab;
using DevExpress.XtraTreeList;
using DevExpress.XtraTreeList.Columns;
using XCI.Core;
using XCI.Data.Entity;
using XCI.Extensions;
using XCI.Helper;
using XCI.Sys;

namespace XCI.Windows.Helper
{
    /// <summary>
    /// Form操作类
    /// </summary>
    public static class WinHelper
    {
        public static readonly Regex DataTagRegex = new Regex(@"g\((.*)\),s\((.*)\)", RegexOptions.Compiled);
        public static readonly Regex UrlParamRegex = new Regex(@"(^|&)?(\w+)=([^&]+)(&|$)?", RegexOptions.Compiled);
        public const string ControlEditValueName = "EditValue";

        /// <summary>
        /// 获取文字的大小
        /// </summary>
        /// <param name="graphics">绘图对象</param>
        /// <param name="text">文本</param>
        /// <param name="font">字体</param>
        /// <returns></returns>
        public static SizeF GetTextSize(Graphics graphics, string text, Font font)
        {
            return graphics.MeasureString(text, font);
        }

        /// <summary>
        /// 获取图片预览窗口大小
        /// </summary>
        public static Size GetImagePreviewSize()
        {
            var width = Convert.ToInt32(Math.Round(Screen.PrimaryScreen.Bounds.Width * 0.8, 0));
            var height = Convert.ToInt32(Math.Round(Screen.PrimaryScreen.Bounds.Height * 0.8, 0));

            return new Size(width, height);
            //var x = Convert.ToInt32((Screen.PrimaryScreen.Bounds.Width - width) / 2);
            //var y = Convert.ToInt32((Screen.PrimaryScreen.Bounds.Height - height) / 2);
            //return new Point(x,y);
        }

        public static void DesignInit()
        {
            DevExpress.Utils.AppearanceObject.DefaultFont = new Font("微软雅黑", 9.75F);
        }

        /// <summary>
        /// 获取操作系统环境变量
        /// </summary>
        /// <param name="name">变量名</param>
        public static string GetEnvironmentVariable(string name)
        {
            string env = Environment.GetEnvironmentVariable(name, EnvironmentVariableTarget.Process);
            if (String.IsNullOrEmpty(env))
            {
                env = Environment.GetEnvironmentVariable(name, EnvironmentVariableTarget.User);
                if (String.IsNullOrEmpty(env))
                {
                    env = Environment.GetEnvironmentVariable(name, EnvironmentVariableTarget.Machine);
                }
            }
            return env;
        }

        /// <summary>
        /// 递归查找控件
        /// </summary>
        /// <param name="controls">控件容器</param>
        /// <param name="name">查找的控件名称</param>
        public static Control FindControl(Control controls, string name)
        {
            if (controls.Controls.Count <= 0) return null;
            foreach (Control item in controls.Controls)
            {
                if (item.Name.Equals(name, StringComparison.CurrentCultureIgnoreCase))
                {
                    return item;
                }
                if (item.Controls.Count <= 0) continue;
                Control control = FindControl(item, name);
                if (control != null)
                {
                    return control;
                }
            }
            return null;
        }


        /// <summary>
        /// 焦点导航到下一个控件或者上一个控件
        /// </summary>
        /// <param name="form">操作的表单</param>
        /// <param name="control">激活控件</param>
        /// <param name="isNext">方向 true 下一个 false 上一个控件</param>
        public static void SelectNextControl(Form form, Control control, bool isNext)
        {
            form.SelectNextControl(control, isNext, true, true, true);
        }

        /// <summary>
        /// 焦点导航到下一个控件或者上一个控件
        /// </summary>
        /// <param name="form">操作的表单</param>
        /// <param name="control">激活控件</param>
        public static void SelectNextControl(Form form, Control control)
        {
            SelectNextControl(form, control, true);
        }

        /// <summary>
        /// 焦点导航到当前激活控件的下一个控件或者上一个控件
        /// </summary>
        /// <param name="form">操作的表单</param>
        /// <param name="isNext">方向 true 下一个 false 上一个控件</param>
        public static void SelectNextControl(Form form, bool isNext)
        {
            SelectNextControl(form, form.ActiveControl, isNext);
        }

        /// <summary>
        /// 焦点导航到当前激活控件的下一个控件或者上一个控件
        /// </summary>
        /// <param name="form">操作的表单</param>
        public static void SelectNextControl(Form form)
        {
            SelectNextControl(form, form.ActiveControl, true);
        }

        /// <summary>
        /// 水平方向让控件紧跟其后
        /// </summary>
        /// <param name="first">第一个控件</param>
        /// <param name="offset">偏移量</param>
        /// <param name="comeAfterControls">其他紧跟控件</param>
        public static void ComeAfterControlHorizontal(Control first, int offset, params Control[] comeAfterControls)
        {
            var total = first.Location.X + first.Width + offset;
            for (var index = 0; index < comeAfterControls.Length; index++)
            {
                var item = comeAfterControls[index];
                item.Location = new Point(total, first.Location.Y);
                total += item.Width + offset;
            }
        }

        /// <summary>
        /// 垂直方向让控件紧跟其下
        /// </summary>
        /// <param name="first">第一个控件</param>
        /// <param name="offset">偏移量</param>
        /// <param name="comeAfterControls">其他紧跟控件</param>
        public static void ComeAfterControlVertical(Control first, int offset, params Control[] comeAfterControls)
        {
            var total = 0;
            foreach (var item in comeAfterControls)
            {
                total += item.Location.Y + item.Height + offset;
                item.Location = new Point(first.Location.X, total);
            }
        }

        /// <summary>
        /// 把控件居中显示
        /// </summary>
        /// <param name="form">操作的表单</param>
        /// <param name="centerControl">要居中的控件</param>
        /// <param name="parentControl">控件的父控件</param>
        /// <param name="isCenterWidth">是否居中宽度</param>
        /// <param name="isCenterHeight">是否居中高度</param>
        public static void CenterControl(Form form, Control centerControl, Control parentControl
            , bool isCenterWidth, bool isCenterHeight)
        {
            if (centerControl == null)
            {
                return;
            }
            if (parentControl == null)
            {
                parentControl = form;
            }
            int x = centerControl.Location.X;
            int y = centerControl.Location.Y;

            if (isCenterWidth)
            {
                x = (parentControl.Width - centerControl.Width) / 2;
            }
            if (isCenterHeight)
            {
                y = (parentControl.Height - centerControl.Height) / 2;
            }
            centerControl.Location = new Point(x, y);
        }

        /// <summary>
        /// 把控件居中显示
        /// </summary>
        /// <param name="form">操作的表单</param>
        /// <param name="centerControl">要居中的控件</param>
        /// <param name="parentControl">控件的父控件</param>
        public static void CenterControl(Form form, Control centerControl, Control parentControl)
        {
            CenterControl(form, centerControl, parentControl, true, true);
        }

        /// <summary>
        /// 居中显示窗口
        /// </summary>
        /// <param name="form">窗口</param>
        public static void CenterForm(Form form)
        {
            int x = (Screen.PrimaryScreen.WorkingArea.Width - form.Width) / 2;
            int y = (Screen.PrimaryScreen.WorkingArea.Height - form.Height) / 2;
            form.Location = new Point(x, y);
        }

        /// <summary>
        /// 设置窗口圆角
        /// </summary>
        /// <param name="width">窗口宽度</param>
        /// <param name="height">窗口高度</param>
        public static Region SetFormRegionRound(int width, int height)
        {
            Rectangle rect = new Rectangle(0, 22, width, height - 22);
            GraphicsPath path = GetRoundedRectPath(rect, 30);
            return new Region(path);
        }

        /// <summary>
        /// 获取圆角路径
        /// </summary>
        /// <param name="rect">矩形</param>
        /// <param name="radius">半径</param>
        private static GraphicsPath GetRoundedRectPath(Rectangle rect, int radius)
        {
            int diameter = radius;
            Rectangle arcRect = new Rectangle(rect.Location, new Size(diameter, diameter));
            GraphicsPath path = new GraphicsPath();
            //   左上角   

            path.AddArc(arcRect, 180, 90);
            //   右上角   

            arcRect.X = rect.Right - diameter;
            path.AddArc(arcRect, 270, 90);
            //   右下角   

            arcRect.Y = rect.Bottom - diameter;
            path.AddArc(arcRect, 0, 90);
            //   左下角   

            arcRect.X = rect.Left;
            path.AddArc(arcRect, 90, 90);
            path.CloseFigure();
            return path;
        }

        /// <summary>
        /// 设置字体信息控件框和字体对话框的通讯
        /// </summary>
        /// <param name="control">字体信息控件框</param>
        /// <param name="dialog">字体对话框</param>
        public static void SetControlFont(Control control, FontDialog dialog)
        {
            if (control.Text.Length > 0)
            {
                dialog.Font = (Font)ObjectHelper.GetObjectFromString(control.Text, typeof(Font));
            }
            if (dialog.ShowDialog() == DialogResult.OK)
            {
                control.Text = ObjectHelper.GetObjectString(dialog.Font);
            }
        }

        /// <summary>
        /// 检测控件是否包括在排除的控件中
        /// </summary>
        /// <param name="control">检测的控件</param>
        /// <param name="exceptControl">排除的控件</param>
        /// <returns>如果包含返回True</returns>
        public static bool HasBaseLayoutItemControl(BaseLayoutItem control, BaseLayoutItem[] exceptControl)
        {
            if (exceptControl != null && exceptControl.Length > 0)
            {
                return exceptControl.Any(item => item.Name.Equals(control.Name));
            }
            return false;
        }

        /// <summary>
        /// 检测控件是否包括在排除的控件中
        /// </summary>
        /// <param name="control">检测的控件</param>
        /// <param name="exceptControl">排除的控件</param>
        /// <returns>如果包含返回True</returns>
        public static bool HasControl(Control control, Control[] exceptControl)
        {
            if (exceptControl != null && exceptControl.Length > 0)
            {
                return exceptControl.Any(item => item.Name.Equals(control.Name));
            }
            return false;
        }

        /// <summary>
        /// 注册Esc关闭窗口事件
        /// </summary>
        /// <param name="ownerForm">所属窗口</param>
        public static void RegEscCloseForm(Form ownerForm)
        {
            ownerForm.KeyPreview = true;
            ownerForm.KeyPress += (o, p) =>
            {
                if (p.KeyChar == 27)
                {
                    ownerForm.Close();
                }
            };
        }

        /// <summary>
        /// 重置窗口大小
        /// </summary>
        /// <param name="visableControl"></param>
        /// <param name="ownerForm"></param>
        /// <param name="linkLab"></param>
        /// <param name="collapse"></param>
        /// <param name="expand"></param>
        /// <param name="collapseString"></param>
        /// <param name="expandString"></param>
        public static void ResizeFormSize(Control visableControl, Form ownerForm, LinkLabel linkLab,
            Image collapse, Image expand, string collapseString, string expandString)
        {
            if (!visableControl.Visible)
            {
                linkLab.Text = collapseString;
                linkLab.Image = collapse;
                int num = ownerForm.Height + visableControl.Height;
                ownerForm.Height = num;
            }
            else
            {
                linkLab.Text = expandString;
                linkLab.Image = expand;
                int num = ownerForm.Height - visableControl.Height;
                ownerForm.Height = num;
            }
            visableControl.Visible = !visableControl.Visible;
            CenterForm(ownerForm);
        }

        /// <summary>
        /// 快速创建窗口,显示到不可见区域,为后期启动窗口加速
        /// </summary>
        /// <typeparam name="T">窗口类型</typeparam>
        public static T InitForm<T>() where T : Form, new()
        {
            T form = new T();
            form.ShowInTaskbar = false;
            form.StartPosition = FormStartPosition.Manual;
            form.Location = new System.Drawing.Point(-100, -100);
            form.Size = new System.Drawing.Size(1, 1);
            form.Show();
            form.Close();
            form.Dispose();
            return form;
        }

        /// <summary>
        /// 是否是设计时环境
        /// </summary>
        /// <param name="ctrl"></param>
        /// <returns></returns>
        public static bool IsDesignMode(Control ctrl)
        {
            if (ctrl != null)
            {
                if (ctrl.Site != null)
                {
                    if (ctrl.Site.DesignMode)
                        return true;
                    if (IsDesignMode(ctrl.Parent))
                        return true;
                    return false;
                }
                if (IsDesignMode(ctrl.Parent))
                    return true;
                return false;
            }
            return false;
        }

        /// <summary>
        /// 添加枚举下拉
        /// </summary>
        /// <param name="box">控件</param>
        /// <param name="enumType">枚举类型</param>
        /// <param name="itemDescriptionDic">项翻译字典</param>
        public static void AddEnum(ImageComboBoxEdit box, Type enumType, Dictionary<string, string> itemDescriptionDic)
        {
            box.Properties.BeginUpdate();
            try
            {
                Array values = System.Enum.GetValues(enumType);
                foreach (object obj in values)
                {
                    string name = obj.ToString();
                    string description = name;
                    if (itemDescriptionDic.ContainsKey(name))
                    {
                        description = itemDescriptionDic[name];
                    }
                    box.Properties.Items.Add(new ImageComboBoxItem(description, obj, -1));
                }
            }
            finally
            {
                box.Properties.EndUpdate();
            }
        }

        /// <summary>
        /// 设置Bar控件字体
        /// </summary>
        /// <param name="barController">BarAndDockingController控件</param>
        public static void SetBarControllerFont(BarAndDockingController barController)
        {
            //if (barController==null)
            //{
            //    return;
            //}
            //var font = new Font(DevExpress.Utils.AppearanceObject.DefaultFont.Name,
            //    DevExpress.Utils.AppearanceObject.DefaultFont.Size - 0.5f);
            //barController.AppearancesBar.ItemsFont = font;

            //barController.AppearancesBackstageView.Button.Options.UseFont = true;
            //barController.AppearancesBackstageView.ButtonDisabled.Options.UseFont = true;
            //barController.AppearancesBackstageView.ButtonHover.Options.UseFont = true;
            //barController.AppearancesBackstageView.ButtonPressed.Options.UseFont = true;

            //barController.AppearancesBackstageView.Button.Font = font;
            //barController.AppearancesBackstageView.ButtonDisabled.Font = font;
            //barController.AppearancesBackstageView.ButtonHover.Font = font;
            //barController.AppearancesBackstageView.ButtonPressed.Font = font;
        }

        public static void SetBarControllerFont(StandaloneBarDockControl standaloneBarDockControl)
        {
            standaloneBarDockControl.AutoSize = true;
        }


        public static void SetStandaloneBarDockControlSize(StandaloneBarDockControl standaloneBarDockControl)
        {
            standaloneBarDockControl.AutoSize = true;
        }

        /// <summary>
        /// 设置图标大小
        /// </summary>
        /// <param name="isLarge">是否大图标(大图标是32,小图标是16)</param>
        /// <param name="imageLists">图标集合</param>
        public static void SetImageListSize(bool isLarge, params ImageCollection[] imageLists)
        {
            int size = 16;
            if (isLarge)
            {
                size = 32;
            }
            foreach (var item in imageLists)
            {
                item.ImageSize = new System.Drawing.Size(size, size);
            }
        }

        /// <summary>
        /// 设置控件日期格式
        /// </summary>
        /// <param name="edit">控件</param>
        /// <param name="format">格式</param>
        public static void SetDateFormat(DateEdit edit, string format)
        {
            edit.Properties.DisplayFormat.FormatType = FormatType.DateTime;
            edit.Properties.DisplayFormat.FormatString = format;

            edit.Properties.EditFormat.FormatType = FormatType.DateTime;
            edit.Properties.EditFormat.FormatString = format;

            edit.Properties.Mask.EditMask = format;
        }

        /// <summary>
        /// 设置控件日期格式
        /// </summary>
        /// <param name="edit">控件</param>
        /// <param name="format">格式</param>
        public static void SetDateFormat(TextEdit edit, string format)
        {
            edit.Properties.DisplayFormat.FormatType = FormatType.DateTime;
            edit.Properties.DisplayFormat.FormatString = format;

            edit.Properties.EditFormat.FormatType = FormatType.DateTime;
            edit.Properties.EditFormat.FormatString = format;

            edit.Properties.Mask.EditMask = format;
        }

        /// <summary>
        /// 设置控件日期格式
        /// </summary>
        /// <param name="edit">控件</param>
        /// <param name="hasTime">是否包含时间</param>
        public static void SetDateFormat(TextEdit edit, bool hasTime)
        {
            SetDateFormat(edit, hasTime ? "yyyy-MM-dd HH:mm:ss" : "yyyy-MM-dd");
        }

        /// <summary>
        /// 设置控件日期格式(默认格式yyyy年MM月dd日)
        /// </summary>
        /// <param name="edit">控件</param>
        /// <param name="hasTime">是否包含时间</param>
        public static void SetDateFormat(DateEdit edit, bool hasTime)
        {
            SetDateFormat(edit, hasTime ? "yyyy-MM-dd HH:mm:ss" : "yyyy-MM-dd");
        }

        /// <summary>
        /// 设置控件日期格式(默认格式yyyy年MM月dd日)
        /// </summary>
        /// <param name="edits">控件数组</param>
        public static void SetDateFormatHasMinute(params DateEdit[] edits)
        {
            if (edits == null || edits.Length == 0) return;
            foreach (DateEdit edit in edits)
            {
                SetDateFormat(edit, "yyyy-MM-dd HH:mm");
            }
        }

        /// <summary>
        /// 设置控件日期格式(默认格式yyyy年MM月dd日) 不包含时间
        /// </summary>
        /// <param name="edits">控件数组</param>
        public static void SetDateFormat(params DateEdit[] edits)
        {
            if (edits == null || edits.Length == 0) return;
            foreach (DateEdit edit in edits)
            {
                SetDateFormat(edit, false);
            }
        }

        /// <summary>
        /// 设置系统皮肤字体
        /// </summary>
        /// <param name="themeSetting">主题设置</param>
        public static void RegisterSkin(ThemeSetting themeSetting)
        {
            BonusSkins.Register();//注册额外扩展皮肤

            if (!string.IsNullOrEmpty(themeSetting.FontName))
            {
                var fontObj = (Font)ObjectHelper.GetObjectFromString(themeSetting.FontName, typeof(Font));
                WindowsFormsSettings.DefaultFont = fontObj;
                WindowsFormsSettings.DefaultMenuFont = fontObj;
                WindowsFormsSettings.DefaultPrintFont = fontObj;
            }

            if (themeSetting.UseDirectX)
            {
                WindowsFormsSettings.ForceDirectXPaint();
            }

            var style = themeSetting.Style;
            switch (style)
            {
                case "Flat":
                    UserLookAndFeel.Default.SetFlatStyle();
                    break;
                case "Office2003":
                    UserLookAndFeel.Default.SetOffice2003Style();
                    break;
                case "Style3D":
                    UserLookAndFeel.Default.SetStyle3D();
                    break;
                case "UltraFlat":
                    UserLookAndFeel.Default.SetUltraFlatStyle();
                    break;
                case "WindowsXP":
                    UserLookAndFeel.Default.SetWindowsXPStyle();
                    break;
                case "Skin":
                    UserLookAndFeel.Default.SetStyle(LookAndFeelStyle.Skin, false, false, themeSetting.SkinName, themeSetting.SvgPaletteName);
                    break;
            }
        }

        /// <summary>
        /// 设置控件焦点
        /// </summary>
        /// <param name="container">所属容器</param>
        /// <param name="propertyName">属性名称</param>
        public static void FocusControl(Control container, string propertyName)
        {
            if (string.IsNullOrEmpty(propertyName)) return;
            foreach (Control control in container.Controls)
            {
                if (control.Tag == null || string.IsNullOrEmpty(control.Tag.ToString())) return;
                var rules = GetTagRule(control.Tag.ToString(), ControlValueTagRuleType.Get);
                foreach (var item in rules)
                {
                    var dataProName = item.Key;
                    if (dataProName.Equals(propertyName))
                    {
                        control.Select();
                        break;
                    }
                }
            }
        }

        /// <summary>
        /// 迭代指定容器中的控件 并执行回调
        /// </summary>
        /// <param name="container">容器</param>
        /// <param name="exec">回调</param>
        /// <param name="recursive">是否递归</param>
        public static void ForEachPanel(Control container, Action<Control> exec, bool recursive = true)
        {
            if (container == null)
            {
                throw new ArgumentNullException(nameof(container));
            }
            foreach (Control control in container.Controls)
            {
                exec?.Invoke(control);
                if (!recursive) continue;

                if (control is SplitContainer scontrol1)
                {
                    ForEachPanel(scontrol1.Panel1, exec);
                    ForEachPanel(scontrol1.Panel2, exec);
                }
                else if (control is SplitContainerControl scontrol)
                {
                    ForEachPanel(scontrol.Panel1, exec);
                    ForEachPanel(scontrol.Panel2, exec);
                }
                else if (control is LayoutControl
                    || control is XtraScrollableControl
                 || control is ScrollableControl
                 || control is GroupBox)
                {
                    ForEachPanel(control, exec);
                }
                else if (control is TabPane tabPane)
                {
                    foreach (NavigationPageBase page in tabPane.Pages)
                    {
                        ForEachPanel(page, exec);
                    }
                }
                else if (control is XtraTabControl tabControl1)
                {
                    foreach (XtraTabPage tabPage in tabControl1.TabPages)
                    {
                        ForEachPanel(tabPage, exec);
                    }
                }
                else if (control is TabControl tabControl)
                {
                    foreach (TabPage tabPage in tabControl.TabPages)
                    {
                        ForEachPanel(tabPage, exec);
                    }
                }
            }
        }

        /// <summary>
        /// 将面板中的控件设为只读
        /// </summary>
        /// <param name="container">容器面板</param>
        /// <param name="isReadOnly">是否设为只读</param>
        /// <param name="exceptControl">排除的控件</param>
        public static void ReadonlyForm(Control container, bool isReadOnly, params Control[] exceptControl)
        {
            ForEachPanel(container, p =>
            {
                if (!HasControl(p, exceptControl))
                {
                    if (p is ButtonEdit edit)
                    {
                        //((ButtonEdit)p).Enabled = isReadOnly;
                        var btns = edit.Properties.Buttons;
                        foreach (EditorButton item in btns)
                        {
                            item.Enabled = !isReadOnly;
                        }
                    }

                    if (p is BaseEdit baseEdit)
                    {
                        baseEdit.Properties.ReadOnly = isReadOnly;
                    }
                }
            });
        }

        /// <summary>
        /// 设置控件状态 启用或者禁用
        /// </summary>
        /// <param name="container">容器面板</param>
        /// <param name="isEnable">是否启用</param>
        /// <param name="exceptControl">排除的控件</param>
        public static void EnableForm(Control container, bool isEnable, params Control[] exceptControl)
        {
            ForEachPanel(container, p =>
            {
                if (!HasControl(p, exceptControl))
                {
                    p.Enabled = isEnable;
                }
            });
        }

        /// <summary>
        /// 清空表单控件
        /// </summary>
        /// <param name="container">控件容器</param>
        /// <param name="exceptControl">排除的控件</param>
        public static void ClearForm(Control container, params Control[] exceptControl)
        {
            ForEachPanel(container, p =>
            {
                if (HasControl(p, exceptControl)) return;
                if (p is BaseEdit baseEdit)
                {
                    baseEdit.EditValue = null;
                }
            });
        }

        /// <summary>
        /// 绑定容器中控件的回车 值变化事件
        /// </summary>
        /// <param name="container">容器面板</param>
        /// <param name="keyPressCallBack"></param>
        /// <param name="exceptControl">排除的控件</param>
        public static void BindEnterToTab(Control container
            , Func<Control, KeyPressEventArgs, bool> keyPressCallBack, params Control[] exceptControl)
        {
            ForEachPanel(container, p =>
            {
                var edit = p as BaseEdit;
                if (edit == null) return;
                if (!edit.TabStop || HasControl(edit, exceptControl)) return;
                edit.Enter += (s, e) => edit.SelectAll();
                edit.KeyPress += (s, e) =>
                {
                    if (keyPressCallBack == null || keyPressCallBack(p, e))
                    {
                        if (e.KeyChar == 13)
                        {
                            if (p is MemoEdit) return;
                            e.Handled = true;
                            var ownerForm = container.FindForm();
                            if (ownerForm == null) return;
                            ownerForm.SelectNextControl(ownerForm.ActiveControl, true, true, true, true);
                        }
                        else if (e.KeyChar == 27)
                        {
                            e.Handled = true;
                            var ownerForm = container.FindForm();
                            if (ownerForm == null) return;
                            ownerForm.SelectNextControl(ownerForm.ActiveControl, false, true, true, true);
                        }
                    }
                };
            });
        }

        /// <summary>
        /// 把对象属性值显示到表单控件中
        /// </summary>
        /// <param name="container">控件容器</param>
        /// <param name="dataItem">数据项</param>
        /// <param name="recursive">是否递归</param>
        public static void SetFormData(Control container, object dataItem, bool recursive = true)
        {
            SetFormData(container, dataItem, recursive, null);
        }

        /// <summary>
        /// 把对象属性值显示到表单控件中
        /// </summary>
        /// <param name="container">控件容器</param>
        /// <param name="dataItem">数据项</param>
        /// <param name="recursive">是否递归</param>
        /// <param name="exceptControl">排除的控件</param>
        public static void SetFormData(Control container, object dataItem,
            bool recursive, params Control[] exceptControl)
        {
            if (dataItem == null) return;
            ForEachPanel(container, p =>
            {
                if (p == null) return;
                if (HasControl(p, exceptControl)) return;
                if (p.Tag == null || string.IsNullOrEmpty(p.Tag.ToString())) return;
                SetFormDataCore(p, dataItem);
            }, recursive);
        }

        /// <summary>
        /// 把对象属性值显示到表单控件中
        /// </summary>
        /// <param name="container">控件容器</param>
        /// <param name="dataItem">数据项</param>
        /// <param name="exceptControl">排除的控件</param>
        public static void SetFormData(BaseLayoutItem container, object dataItem, params LayoutControlItem[] exceptControl)
        {
            if (dataItem == null) return;
            ForEachLayoutControlGroupPanel(container, p =>
            {
                if (p == null || p.Control == null) return;
                if (HasBaseLayoutItemControl(p, exceptControl)) return;
                if (p.Control.Tag == null || string.IsNullOrEmpty(p.Control.Tag.ToString())) return;
                SetFormDataCore(p.Control, dataItem);
            });
        }

        private static void SetFormDataCore(Control c, object dataItem)
        {
            var rules = GetTagRule(c.Tag.ToString(), ControlValueTagRuleType.Set);
            foreach (var item in rules)
            {
                var dataProName = item.Key;
                var controlProName = item.Value;
                var hasPro = true;

                object dataProValue = null;
                if (dataItem is IDictionary dic)
                {
                    hasPro = dic.Contains(dataProName);
                    if (hasPro)
                    {
                        dataProValue = dic[dataProName];
                    }
                }
                else
                {
                    hasPro = dataItem.GetType().GetProperty(dataProName) != null;
                    if (hasPro)
                    {
                        dataProValue = ObjectHelper.GetObjectValue(dataItem, dataProName);
                    }
                }
                if (!hasPro) //没有指定的属性名称
                {
                    return;
                }

                //if (controlProName.Equals(ControlEditValueName))
                //{
                //    ((BaseEdit)c).EditValue = dataProValue;
                //}
                //else if (c is CheckedComboBoxEdit edit)
                //{
                //    edit.SetEditValue(dataProValue);
                //}
                //else
                {
                    ObjectHelper.SetObjectValue(c, controlProName, dataProValue);
                }
            }
        }

        /// <summary>
        /// 把表单中控件值写到对象属性中
        /// </summary>
        /// <param name="container">控件容器</param>
        /// <param name="dataItem">数据项</param>
        /// <param name="recursive">是否递归</param>
        public static void GetFormData(Control container, object dataItem, bool recursive = true)
        {
            GetFormData(container, dataItem, recursive, null);
        }

        /// <summary>
        /// 把表单中控件值写到对象属性中
        /// </summary>
        /// <param name="container">控件容器</param>
        /// <param name="dataItem">数据项</param>
        /// <param name="recursive">是否递归</param>
        /// <param name="exceptControl">排除的控件</param>
        public static void GetFormData(Control container, object dataItem, bool recursive, params Control[] exceptControl)
        {
            if (dataItem == null) return;
            ForEachPanel(container, p =>
            {
                if (p == null) return;
                if (HasControl(p, exceptControl)) return;
                if (p.Tag == null || string.IsNullOrEmpty(p.Tag.ToString())) return;
                GetFormDataCore(p, dataItem);
            }, recursive);
        }

        /// <summary>
        /// 把表单中控件值写到对象属性中
        /// </summary>
        /// <param name="container">控件容器</param>
        /// <param name="dataItem">数据项</param>
        /// <param name="exceptControl">排除的控件</param>
        public static void GetFormData(BaseLayoutItem container, object dataItem, params LayoutControlItem[] exceptControl)
        {
            if (dataItem == null) return;
            ForEachLayoutControlGroupPanel(container, p =>
            {
                if (p == null || p.Control == null) return;
                if (HasBaseLayoutItemControl(p, exceptControl)) return;
                if (p.Control.Tag == null || string.IsNullOrEmpty(p.Control.Tag.ToString())) return;
                GetFormDataCore(p.Control, dataItem);
            });
        }

        /// <summary>
        /// 迭代指定容器中的控件 并执行回调
        /// </summary>
        /// <param name="container">容器</param>
        /// <param name="exec">回调</param>
        public static void ForEachLayoutControlGroupPanel(BaseLayoutItem container, Action<LayoutControlItem> exec)
        {
            if (container == null)
            {
                throw new ArgumentNullException(nameof(container));
            }

            if (container is LayoutControlItem controlItem)
            {
                exec?.Invoke(controlItem);
            }
            else if (container is LayoutControlGroup controlGroup)
            {
                foreach (BaseLayoutItem control in controlGroup.Items)
                {
                    ForEachLayoutControlGroupPanel(control, exec);
                }
            }
            else if (container is TabbedControlGroup tabbedControlGroup)
            {
                foreach (BaseLayoutItem layoutItem in tabbedControlGroup.TabPages)
                {
                    ForEachLayoutControlGroupPanel(layoutItem, exec);
                }
            }
        }

        private static void GetFormDataCore(Control c, object dataItem)
        {
            var rules = GetTagRule(c.Tag.ToString(), ControlValueTagRuleType.Get);
            foreach (var item in rules)
            {
                var dataProName = item.Key;
                var controlProName = item.Value;

                var controlProValue = ObjectHelper.GetObjectValue(c, controlProName);
                if (dataItem is IDictionary dic)
                {
                    dic[dataProName] = controlProValue;
                }
                else
                {
                    ObjectHelper.SetObjectValue(dataItem, dataProName, controlProValue);
                }
            }
        }

        private static List<KeyValue> GetTagRule(string tagString, ControlValueTagRuleType ruleType)
        {
            var result = DataTagRegex.Match(tagString);
            if (result.Success && result.Groups.Count >= 3) //读写各自指定的情况
            {
                var rule = string.Empty;
                if (ruleType == ControlValueTagRuleType.Get)
                {
                    rule = result.Groups[1].Value;
                }
                else if (ruleType == ControlValueTagRuleType.Set)
                {
                    rule = result.Groups[2].Value;
                }
                return ParseTagRule(rule);
            }

            //读写相同的情况
            return ParseTagRule(tagString);
        }

        /// <summary>
        /// Tag规则:
        /// 1.读写相同,多个规则逗号隔开
        ///  1) 一一对应:(数据属性名:控件属性名,...)
        ///  2) 只指定数据属性名,控件属性名默认是EditValue
        /// 2.读写各自指定,完整格式:g(数据属性名:控件属性名,...),s(数据属性名:控件属性名,...) 顺序不能变
        ///  1) 只指定读或者写,要求格式要写完整,括号里面的内容可以省略
        /// </summary>
        private static List<KeyValue> ParseTagRule(string rule)
        {
            var rules = new List<KeyValue>();
            if (string.IsNullOrEmpty(rule)) return rules;
            var sz = rule.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            for (int i = 0; i < sz.Length; i++)
            {
                try
                {
                    var item = sz[i];
                    var index = item.IndexOf(':');
                    var dataProName = item;
                    var controlProName = ControlEditValueName;
                    if (index > -1)
                    {
                        dataProName = item.Substring(0, index);
                        controlProName = item.Substring(index + 1);
                    }

                    if (string.IsNullOrEmpty(dataProName) || string.IsNullOrEmpty(controlProName)) continue;
                    if (rules.Any(p => p.Key.Equals(dataProName)))
                    {
                        continue;
                    }
                    rules.Add(new KeyValue(dataProName, controlProName));
                }
                catch (Exception e)
                {
                    throw new ControlValueException(e);
                }
            }
            return rules;
        }

        /// <summary>
        /// 获取Url字符串中的参数信息
        /// </summary>
        /// <param name="url">Url</param>
        /// <exception cref="System.ArgumentNullException">无效的 URI: 此 URI 为空。</exception>
        /// <returns>返回Url中的参数字典</returns>
        public static Dictionary<string, string> ParseUrlParamDic(string url)
        {
            if (string.IsNullOrEmpty(url))
            {
                throw new ArgumentNullException(nameof(url), "无效的 URI: 此 URI 为空。");
            }

            string ps = url;
            Dictionary<string, string> dic = new Dictionary<string, string>();
            int questionMarkIndex = url.IndexOf('?');
            if (questionMarkIndex != -1)
            {
                ps = url.Substring(questionMarkIndex + 1);
            }

            // 开始分析参数对    
            MatchCollection mc = UrlParamRegex.Matches(ps);
            foreach (Match m in mc)
            {
                dic.Add(m.Result("$2"), m.Result("$3"));
            }
            return dic;
        }

        /// <summary>
        /// 把宏变量插入到文本框
        /// </summary>
        /// <param name="entity">宏变量实体</param>
        /// <param name="editBox">文本框</param>
        public static void InsertMacroVariable(MacroVariableAttribute entity, TextEdit editBox)
        {
            if (editBox == null) return;
            string template = editBox.Text;
            int startIndex = editBox.SelectionStart;
            if (startIndex == 0 || startIndex > template.Length)
            {
                template = string.Concat(template, entity.Name);
            }
            else
            {
                template = template.Insert(startIndex, entity.Name);
            }
            editBox.Text = template;
        }

        /// <summary>
        /// 写日志到文本框
        /// </summary>
        /// <param name="edit">文本框</param>
        /// <param name="msg">消息</param>
        public static void WriteLogToTextBox(TextEdit edit, string msg)
        {
            WriteLogToTextBox(edit, msg, true);
        }

        /// <summary>
        /// 情况文本框中日志
        /// </summary>
        /// <param name="edit">文本框</param>
        public static void CleanLogToTextBox(TextEdit edit)
        {
            Action action = () =>
            {
                edit.Text = string.Empty;
                edit.ScrollToCaret();
            };
            if (edit.InvokeRequired)
            {
                edit.Invoke(action);
            }
            else
            {
                action();
            }
        }

        /// <summary>
        /// 写日志到文本框
        /// </summary>
        /// <param name="edit">文本框</param>
        /// <param name="msg">消息</param>
        /// <param name="isNewLine">是否换行</param>
        public static void WriteLogToTextBox(TextEdit edit, string msg, bool isNewLine)
        {
            Action action = () =>
            {
                edit.Text += msg;
                if (isNewLine)
                {
                    edit.Text += "\r\n";
                }
                edit.SelectionStart = edit.Text.Length;
                edit.ScrollToCaret();
            };
            if (edit.InvokeRequired)
            {
                edit.Invoke(action);
            }
            else
            {
                action();
            }
        }

        private static string lastImeName;
        /// <summary>
        /// 切换输入法
        /// </summary>
        /// <param name="imeModex">输入法模式</param>
        /// <param name="imeSetting">输入法设置</param>
        public static void SwitchIme(ImeModex imeModex, ImeSetting imeSetting)
        {
            string imeName = null;
            switch (imeModex)
            {
                case ImeModex.English:
                    imeName = imeSetting.EnglishIme;
                    break;
                case ImeModex.Chinese:
                    imeName = imeSetting.ChineseIme;
                    break;
            }
            if (string.IsNullOrEmpty(imeName)) return;
            lastImeName = ImeHelper.GetCurrentIme();
            if (imeName.Equals(lastImeName)) return;
            ImeHelper.SwtichIme(imeName);
        }

        /// <summary>
        /// 还原默认输入法
        /// </summary>
        public static void RestoreIme()
        {
            if (string.IsNullOrEmpty(lastImeName)) return;
            if (lastImeName.Equals(ImeHelper.GetCurrentIme())) return;
            ImeHelper.SwtichIme(lastImeName);
        }

        /// <summary>
        /// 绑定控件和对象的双向通讯(把对象的值自动赋值给控件 控件值发生变化时自动改变对象的属性值)
        /// </summary>
        /// <param name="container">控件容器</param>
        /// <param name="target">目标对象</param>
        public static void BindCustomPropertyControlValue(Control container, object target)
        {
            ForEachPanel(container, p =>
            {
                var editor = p as BaseEdit;
                if (editor == null) return;
                if (p.Tag == null || string.IsNullOrEmpty(p.Tag.ToString())) return;
                string propertyName = p.Tag.ToString();
                if (target != null)
                {
                    var pValue = ObjectHelper.GetObjectPropertys(target, propertyName);
                    editor.EditValue = pValue;
                }

                editor.EditValueChanged += (o, e) =>
                {
                    BaseEdit edit = (BaseEdit)o;
                    if (edit.Tag == null || string.IsNullOrEmpty(edit.Tag.ToString())) return;
                    string _propertyName = edit.Tag.ToString();
                    string _propertyValue = ObjectHelper.GetObjectString(edit.EditValue);
                    ObjectHelper.SetObjectPropertys(target, _propertyName, _propertyValue);
                };
            });
        }

        /// <summary>
        /// 缓存的类型
        /// </summary>
        private static readonly List<Type> CacheFormTypes = new List<Type>();

        //public static Form CreateLoginForm(params string[] args)
        //{
        //    var loginForm = AppData.LoginForm;
        //    //loginForm.Args = args;
        //    return loginForm as Form;
        //}

        //public static Form CreateMainForm(params string[] args)
        //{
        //    var mainForm = AppData.MainForm;
        //    //mainForm.Args = args;
        //    return mainForm as Form;
        //}

        /// <summary>
        /// 获取图片文件夹
        /// </summary>
        /// <param name="isLarge">是否大图标</param>
        public static string GetImageDirectory(bool isLarge)
        {
            string dir = isLarge ? "Assets\\Toolbar\\32" : "Assets\\Toolbar\\16";
            return Path.Combine(SystemDirectory.RootDirectory, dir);
        }

        private static List<Type> InitTypesCache()
        {
            if (CacheFormTypes.Count > 0) return CacheFormTypes;
            var files = new List<string>();
            var baseDir = AppDomain.CurrentDomain.BaseDirectory;
            var subs = new[] { "addIns", "lib", "extensions", "plugins", };
            files.AddRange(Directory.GetFiles(baseDir));
            foreach (var item in subs)
            {
                string path = Path.Combine(baseDir, item);
                if (Directory.Exists(path))
                {
                    files.AddRange(Directory.GetFiles(path));
                }
            }
            var vFiles = files.Where(p => p.ToLower().EndsWith(".dll")
                || p.ToLower().EndsWith(".exe")).ToArray();
            var ts = TypeHelper.LoadTypes(vFiles);
            CacheFormTypes.AddRange(ts);
            return CacheFormTypes;
        }

        public static List<FormCaptionAttribute> GetFormProvider()
        {
            var allTypes = InitTypesCache();
            var types = allTypes.Where(p => ObjectHelper.CheckSubClass(p, typeof(Form)));
            var list = new List<FormCaptionAttribute>();
            foreach (Type type in types)
            {
                var attr = ObjectHelper.GetAttribute<FormCaptionAttribute>(type);
                if (attr == null || !attr.Visible)
                {
                    continue;
                }
                attr.Code = ObjectHelper.GetTypeFullName(type);
                if (!string.IsNullOrEmpty(attr.Name))
                {
                    attr.NameSpell = SpellHelper.GetSpell(attr.Name);
                }
                list.Add(attr);
            }
            return list;
        }

        public static List<WidgetCaptionAttribute> GetWidgetProvider()
        {
            var allTypes = InitTypesCache();
            var types = ObjectHelper.GetSubClass(allTypes,false,true, typeof(UserControl));
            var list = new List<WidgetCaptionAttribute>();
            foreach (Type type in types)
            {
                var attr = ObjectHelper.GetAttribute<WidgetCaptionAttribute>(type);
                if (attr == null) continue;
                attr.Code = ObjectHelper.GetTypeFullName(type);
                if (!string.IsNullOrEmpty(attr.Name))
                {
                    attr.Spell = SpellHelper.GetSpell(attr.Name);
                }
                list.Add(attr);
            }
            return list;
        }

        /// <summary>
        /// 获取表格配置
        /// </summary>
        public static string GetGridViewSetting(GridView gridView)
        {
            gridView.ClearSorting();
            gridView.ClearColumnsFilter();
            gridView.ApplyFindFilter(null);
            var ms = new MemoryStream();
            gridView.SaveLayoutToStream(ms, OptionsLayoutBase.FullLayout);
            ms.Seek(0, System.IO.SeekOrigin.Begin);
            return Encoding.UTF8.GetString(ms.ToArray());
        }

        /// <summary>
        /// 应用表格二进制配置
        /// </summary>
        public static void SetGridViewSetting(GridView gridView, string setting)
        {
            if (string.IsNullOrEmpty(setting)) return;
            var data = Encoding.UTF8.GetBytes(setting);
            MemoryStream ms = IOHelper.ToMemoryStream(data);
            if (ms == null) return;
            gridView.RestoreLayoutFromStream(ms, OptionsLayoutBase.FullLayout);
            ms.Seek(0, System.IO.SeekOrigin.Begin);
        }

        /// <summary>
        /// 获取Tree二进制配置
        /// </summary>
        public static string GetTreeSetting(TreeList tree)
        {
            tree.ClearSorting();
            tree.ClearColumnsFilter();
            tree.ApplyFindFilter(null);

            var ms = new MemoryStream();
            tree.SaveLayoutToStream(ms, OptionsLayoutBase.FullLayout);
            ms.Seek(0, System.IO.SeekOrigin.Begin);
            return Encoding.UTF8.GetString(ms.ToArray());
        }

        /// <summary>
        /// 应用Tree二进制配置
        /// </summary>
        public static void SetTreeSetting(TreeList tree, string setting)
        {
            if (string.IsNullOrEmpty(setting)) return;
            var data = Encoding.UTF8.GetBytes(setting);
            MemoryStream ms = IOHelper.ToMemoryStream(data);
            if (ms == null) return;
            tree.RestoreLayoutFromStream(ms, OptionsLayoutBase.FullLayout);
            ms.Seek(0, System.IO.SeekOrigin.Begin);
        }

        /// <summary>
        /// 自动生成表格列
        /// </summary>
        public static void AutoBuildGridColumn(GridView gridView, EntityData metadata)
        {
            if (metadata == null) return;

            gridView.OptionsView.ShowGroupPanel = false;
            gridView.OptionsView.ColumnAutoWidth = false;
            gridView.IndicatorWidth = 35;
            gridView.RowHeight = 30;
            gridView.OptionsBehavior.Editable = false;
            gridView.OptionsBehavior.AutoPopulateColumns = false;
            gridView.FocusRectStyle = DevExpress.XtraGrid.Views.Grid.DrawFocusRectStyle.None;
            gridView.OptionsCustomization.AllowFilter = false;
            gridView.OptionsSelection.CheckBoxSelectorColumnWidth = 30;
            gridView.OptionsSelection.EnableAppearanceHideSelection = false;
            gridView.OptionsSelection.EnableAppearanceFocusedCell = false;
            gridView.OptionsSelection.EnableAppearanceFocusedRow = true;
            gridView.OptionsSelection.MultiSelect = true;
            gridView.OptionsSelection.MultiSelectMode = GridMultiSelectMode.CheckBoxRowSelect;
            gridView.OptionsSelection.ResetSelectionClickOutsideCheckboxSelector = true;
            gridView.Columns.Clear();

            int index = 0;
            foreach (var item in metadata.AllColumns)
            {
                var col = item.Value;
                var column = new GridColumn();
                column.VisibleIndex = index + 1;
                column.Name = $"col_{StringHelper.Guid()}";
                column.FieldName = col.Name;
                column.Caption = col.Caption ?? col.Name;
                column.OptionsColumn.AllowEdit = false;

                column.AppearanceCell.Options.UseTextOptions = true;
                column.AppearanceCell.TextOptions.HAlignment = HorzAlignment.Center;

                column.AppearanceHeader.Options.UseTextOptions = true;
                column.AppearanceHeader.TextOptions.HAlignment = HorzAlignment.Center;

                var dataType = col.Property.Property.PropertyType;
                if (dataType == typeof(DateTime) || dataType == typeof(DateTime?))
                {
                    column.DisplayFormat.FormatType = DevExpress.Utils.FormatType.DateTime;
                    column.DisplayFormat.FormatString = "yyyy-MM-dd HH:mm:ss";
                }
                else if (dataType == typeof(decimal) || dataType == typeof(decimal?))
                {
                    column.DisplayFormat.FormatType = DevExpress.Utils.FormatType.Numeric;
                    column.DisplayFormat.FormatString = "#.##";
                }

                column.Visible = col.Visable;

                gridView.Columns.Add(column);
                index++;
            }
            gridView.BestFitColumns();
        }

        /// <summary>
        /// 自动生成树控件列
        /// </summary>
        public static void AutoBuildTreeColumn(TreeList tree, EntityData metadata)
        {
            if (metadata == null) return;

            tree.OptionsBehavior.Editable = false;
            tree.OptionsBehavior.EnableFiltering = false;
            tree.OptionsCustomization.AllowSort = false;
            //tree.OptionsBehavior.AllowIndeterminateCheckState = false;
            tree.OptionsBehavior.AutoPopulateColumns = true;
            tree.OptionsView.AutoWidth = true;
            tree.OptionsView.ShowFilterPanelMode = DevExpress.XtraTreeList.ShowFilterPanelMode.Never;
            //tree.ShowButtonMode = ShowButtonModeEnum.ShowOnlyInEditor;
            tree.OptionsSelection.EnableAppearanceFocusedCell = false;
            tree.OptionsFilter.FilterMode = FilterMode.Extended;
            //tree.OptionsBehavior.EnableFiltering = true;
            tree.OptionsView.ShowCheckBoxes = false;
            tree.OptionsView.FocusRectStyle = DevExpress.XtraTreeList.DrawFocusRectStyle.None;
            tree.IndicatorWidth = 35;
            tree.RowHeight = 30;
            tree.Columns.Clear();

            int index = 0;
            foreach (var item in metadata.AllColumns)
            {
                var col = item.Value;

                TreeListColumn column = tree.Columns.Add();
                column.VisibleIndex = index + 1;
                column.Name = $"tcol_{StringHelper.Guid()}";
                column.FieldName = col.Name;
                column.Caption = col.Caption ?? col.Name;
                column.AppearanceCell.Options.UseTextOptions = true;
                column.AppearanceCell.TextOptions.HAlignment = HorzAlignment.Center;

                column.AppearanceHeader.Options.UseTextOptions = true;
                column.AppearanceHeader.TextOptions.HAlignment = HorzAlignment.Center;

                column.OptionsColumn.AllowEdit = false;
                var dataType = col.Property.Property.PropertyType;
                if (dataType == typeof(DateTime) || dataType == typeof(DateTime?))
                {
                    column.Format.FormatType = DevExpress.Utils.FormatType.DateTime;
                    column.Format.FormatString = "yyyy-MM-dd HH:mm:ss";
                }
                else if (dataType == typeof(decimal) || dataType == typeof(decimal?))
                {
                    column.Format.FormatType = DevExpress.Utils.FormatType.Numeric;
                    column.Format.FormatString = "#.##";
                }

                column.Visible = col.Visable;

                index++;
            }
            tree.BestFitColumns();
        }

        /// <summary>
        /// 导出文件对话框
        /// </summary>
        /// <param name="c">LoadMask控件</param>
        /// <param name="func"></param>
        /// <param name="defaultFileName"></param>
        public static void ExcelExportCore(Control c, Func<byte[]> func, string defaultFileName = null)
        {
            var fileSave = new SaveFileDialog();
            fileSave.AddExtension = true;
            fileSave.DefaultExt = "xlsx";
            fileSave.FileName = defaultFileName;
            fileSave.Filter = "Excel文件|*.xlsx";
            if (fileSave.ShowDialog() == DialogResult.OK)
            {
                IOverlaySplashScreenHandle handle = null;
                try
                {
                    if (c != null)
                    {
                        handle = SplashHelper.ShowProgressPanel(c);
                    }
                    var bytes = func();
                    IOHelper.WriteFile(bytes, fileSave.FileName);
                }
                finally
                {
                    if (c != null)
                    {
                        SplashHelper.CloseProgressPanel(handle);
                    }
                }

                if (DialogResult.Yes == MessageBoxHelper.ShowMessageYesNo("导出成功，现在需要打开此文件吗？"))
                {
                    try
                    {
                        Process.Start(fileSave.FileName);
                    }
                    catch (Exception e)
                    {
                        DebugHelper.Catch(e);
                    }
                }
            }

            fileSave.Dispose();
        }

        public const string pathSeparator = "\\";

        /// <summary>
        /// 根据服务端路径，构建本地路径
        /// </summary>
        /// <param name="serverPath">根据服务端路径</param>
        public static string BuildLocalPathByServerPath(string serverPath)
        {
            if (serverPath.IsEmpty())
            {
                return serverPath;
            }
            serverPath = serverPath.Replace("/", "\\");
            if (serverPath.Substring(0, 1) != "\\")
            {
                serverPath = pathSeparator + serverPath;
            }
            return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, serverPath.Substring(1));
        }

    }
}